#include <assert.h>
#include <stdexcept>

#include <config.h>
#include <Tools/String.h>
#include "IndexDB.h"

SizeType IndexDB::findFirstFree() const
{
	assert(myFile.IsOpened());
	for( ; iFirstFree <= MAX_INDEXDB_SIZE; ++iFirstFree)
	{
		SizeType iFirstRecord = INVALID_SIZE;
		if(sizeof(SizeType) != myFile.PRead(&iFirstRecord, sizeof(SizeType), iFirstFree * sizeof(sFileRecord)))
			throw std::runtime_error(String("Cannot read from IndexDB! IndexDB %s corrupted?", myFile.GetFileName().c_str()));

		if(0 == iFirstRecord)
			break;
	}; 
	
	return iFirstFree;
};

IndexDB::IndexDB(const char * filePath) : myFile(filePath, FM_OpenRW), iFirstFree(0)
{
	if(false == myFile.IsOpened())
	{
		myFile.Open(filePath, FM_OpenRW | FM_Create);
		if(false == myFile.IsOpened())
			throw std::runtime_error(String("Cannot create new IndexDB %s!", filePath));

		if(false == myFile.Truncate(MAX_INDEXDB_SIZE * sizeof(sFileRecord)))
			throw std::runtime_error(String("Cannot allocate space for IndexDB %s!", filePath));
	};

	iFirstFree = findFirstFree();
};

IndexDB::~IndexDB()
{

};
	
bool IndexDB::IsFull() const
{
	return findFirstFree() == MAX_INDEXDB_SIZE;
};

SizeType IndexDB::CreateFile(SizeType iFirstRecordID, SizeType iLastRecordID)
{
	/* need locking here! */
	const SizeType iFileRecord = findFirstFree();
    	if(MAX_INDEXDB_SIZE == iFileRecord)
		return INVALID_SIZE;
		
	sFileRecord myFileRecord = { iFirstRecordID, iLastRecordID };
	if(sizeof(sFileRecord) != myFile.PWrite(&myFileRecord, sizeof(sFileRecord), iFileRecord * sizeof(sFileRecord)))
		throw std::runtime_error(String("Cannot create file %"PRId64" into IndexDB %s", iFileRecord, myFile.GetFileName().c_str()));
	
	return iFileRecord;
};
	
bool IndexDB::UpdateFirstRecord(SizeType iFileID, SizeType iFirstRecordID)
{
	return (sizeof(SizeType) == myFile.PWrite(&iFirstRecordID, sizeof(SizeType), iFileID * sizeof(sFileRecord)));
};

bool IndexDB::UpdateLastRecord(SizeType iFileID, SizeType iLastRecordID)
{
	return (sizeof(SizeType) == myFile.PWrite(&iLastRecordID, sizeof(SizeType), iFileID * sizeof(sFileRecord) + sizeof(SizeType)));
};

SizeType IndexDB::GetFirstRecord(SizeType iFileID) const
{
	SizeType iResult = 0;
	myFile.PRead(&iResult, sizeof(SizeType), iFileID * sizeof(sFileRecord));
	return iResult;
};

SizeType IndexDB::GetLastRecord(SizeType iFileID) const
{
	SizeType iResult = 0;
	myFile.PRead(&iResult, sizeof(SizeType), iFileID * sizeof(sFileRecord) + sizeof(SizeType));
	return iResult;
};

bool IndexDB::GetFileRecord(SizeType iFileID, sFileRecord & result) const
{
	return (sizeof(sFileRecord) == myFile.PRead(&result, sizeof(sFileRecord), iFileID * sizeof(sFileRecord)));
};

